--[[

Messages:
   PDKPM GUILD    AUTH <md5>
   PDKPM WHISPER  REAUTH

]]

assert(PandaDKPMaster, "PandaDKPMaster not found!")

------------------------------
--      Are you local?      --
------------------------------
local PandaDKPMaster = PandaDKPMaster
local Auth =
{
   LastAuth = 0,   -- the last time we sent our authentication
}
PandaDKPMaster.Auth = Auth

------------------------------
--        Constants         --
------------------------------
local kReauthTime = 30
local kAuthTime = 60 * 60 * 2    -- A user is authorized for two hours
local kFailedTime = 60 * 5       -- A user will be requested to reauth after 5 minutes of failed time


-- Called when the mod is enabled
function Auth:Enable()
end

--PandaDKPMaster:Print(PandaDKPMaster.Auth:CreateMD5('Isotropic'))


function Auth:HandleAuth(sender, md5)
   -- Create our own version of the MD5 string
   local check = PandaDKPMaster.Auth:CreateMD5(sender)
   
   -- Compare the two, if they match then they are authenticated, else not authorized
   if (md5 == check) then
      PandaDKPMaster.Auth:UserAuthorized(sender)
   else
      PandaDKPMaster.Auth:UserNotAuthorized(sender)
   end
end


function Auth:HandleReauth()
   -- If we have not sent an authentication request in the last 30 seconds, send one
   if (Auth.LastAuth + kReauthTime < time()) then
   
      -- Send a guild wide AUTH message
      local md5 = PandaDKPMaster.Auth:CreateMD5(UnitName("player"))
      PandaDKPMaster.Comm:Send("GUILD", string.format("AUTH %s", md5))
      
      -- Store the time we sent it
      PandaDKPMaster.Auth.LastAuth = time()
   end
end


-- Creates an MD5 string from the user's name and the shared secret
function Auth:CreateMD5(user)
   return PandaDKPMaster.MD5Lib:MD5(user .. PandaDKPMaster.db.realm.DbPassword)
end


-- Marks a user as authorized and pulls any of their messages out of the unauthorized queue and puts them
-- into the normal queue.
function Auth:UserAuthorized(user)
   -- If the user is in the Failed list, remove them from that list
   PandaDKPMaster.db.realm.Auth.Failed[user] = nil
   
   -- Add or update the user in the Authorized list. Value is the time they last authorized
   PandaDKPMaster.db.realm.Auth.Authorized[user] = time()
   
   -- Tell the message queue to move any unauthorized messages from this user to the normal queue
   PandaDKPMaster.Messages:AuthorizeSender(user)
end


-- Marks a user as unauthorized and pulls any of their messages out of the normal queue and puts them
-- into the unauthorized queue.
function Auth:UserNotAuthorized(user)
   -- If the user is in the Authorized list, remove them
   PandaDKPMaster.db.realm.Auth.Authorized[user] = nil
   
   -- Add the user to the failed list
   PandaDKPMaster.db.realm.Auth.Failed[user] = time()
   
   -- Tell the message queue to move any messages from this user from the normal queue to the unauthorized queue
   PandaDKPMaster.Messages:DeauthorizeSender(user)
end


-- Return true if the user is authorized. If the user is not authorized or their authorization has
-- expired, this may send a reauth request.
function Auth:CheckAuthorization(user)
   if (nil ~= PandaDKPMaster.db.realm.Auth.Authorized[user]) then
      -- See if the authorization has expired
      local lastAuth = PandaDKPMaster.db.realm.Auth.Authorized[user]
      if (lastAuth + kAuthTime < time()) then
         -- The user is no longer authorized. Deauthorize the user and send a REAUTH whisper
         Auth:UserNotAuthorized(user)
         PandaDKPMaster.Comm:Send("WHISPER", "REAUTH", user)
      else
         -- The user is still authorized
         return true
      end
   elseif (nil ~= PandaDKPMaster.db.realm.Auth.Failed[user]) then
      local lastAuth = PandaDKPMaster.db.realm.Auth.Failed[user]
      if (lastAuth + kFailedTime < time()) then
         PandaDKPMaster.Comm:Send("WHISPER", "REAUTH", user)
      end
   else
      -- We didn't know about the user, so put them in the failed list
      Auth:UserNotAuthorized(user)
      PandaDKPMaster.Comm:Send("WHISPER", "REAUTH", user)
   end
   
   return false
end


function Auth:SetPassword(password)
   -- If the password is not the same as the current one, we have to completely reauthorize
   if (password ~= PandaDKPMaster.db.realm.DbPassword) then
      -- Set the password
      PandaDKPMaster.db.realm.DbPassword = password
      
      -- Go through all previously failed and authorized users and ask them to reauthorize
      for user,time in pairs(PandaDKPMaster.db.realm.Auth.Failed) do PandaDKPMaster.Comm:Send("WHISPER", "REAUTH", user) end
      for user,time in pairs(PandaDKPMaster.db.realm.Auth.Authorized) do PandaDKPMaster.Comm:Send("WHISPER", "REAUTH", user) end
      PandaDKPMaster.db.realm.Auth.Failed = {}
      PandaDKPMaster.db.realm.Auth.Authorized = {}
      
      -- Send a new authorization
      Auth.LastAuth = 0
      Auth:HandleReauth()
   end
end